//
//  pushstream.c
//  PushStream
//
//  Created by yuanxuzhen on 2021/4/15.
//

#include "pushstream.h"
#include "librtmp/rtmp.h"

/*
 flv文件 头部有9个字节，
 第一个字节是字母F,
 第二个字节是L,
 第三个字节是V,
 第四个字节是版本号，
 第五个字节 1-5位保留，必须是0，第6位是否有音频tag 第7位保留必须是0，第8位是否有视频tag
 第六到九字节代表header的大小，必须是9
 */

static int status = 1;
void set_status(int state){
    status = state;
}

static FILE* open_flv(char* flvaddr){
    FILE* fp = NULL;
    fp = fopen(flvaddr, "rb");
    if(!fp){
        printf("failed to open flv:%s", flvaddr);
        return NULL;
    }
    fseek(fp, 9, SEEK_SET); //跳过flv头 9个字节
    fseek(fp, 4, SEEK_CUR); //跳过pretagsize 4个字节
    return fp;

}

static RTMP* connect_rtmp_server(char* rtmp_addr){
    RTMP* rtmp = NULL;
    rtmp = RTMP_Alloc();
    if(!rtmp){
        printf("NO Memory");
        goto __ERROR;
    }
    RTMP_Init(rtmp);
    //设置rtmp的超时时间和rtmp的连接地址
    rtmp->Link.timeout = 10;
    RTMP_SetupURL(rtmp, rtmp_addr);
    //设置推流还是拉流，设置开启是推流，不设置是拉流
    RTMP_EnableWrite(rtmp);

    //建立链接
    if(!RTMP_Connect(rtmp, NULL)){
        printf("failed to connect");
        goto __ERROR;
    }
    //创建流
    RTMP_ConnectStream(rtmp, 0);
    return rtmp;
__ERROR:
    if(rtmp){
        RTMP_Close(rtmp);
        RTMP_Free(rtmp);
    }
    
    return NULL;
}
static RTMPPacket *alloc_packet(){
    RTMPPacket *pack = NULL;
//    pack = （RTMPPacket*）malloc(sizeof(RTMPPacket));
    pack =(RTMPPacket*)malloc(sizeof(RTMPPacket));
    if(!pack){
        printf("NO Memory alloc_packet");
        return NULL;
    }
    RTMPPacket_Alloc(pack, 64 * 1024);
    RTMPPacket_Reset(pack);
    pack->m_hasAbsTimestamp = 0;
    pack->m_nChannel = 0x4;
    
    return pack;
}

static int read_u8(FILE* fp, unsigned int *u8){
    unsigned int tmp;
    if(fread(&tmp, 1, 1, fp) != 1){
        printf("Failed to read_u8!\n");
        return -1;
    }
    
    *u8 = tmp & 0xFF;
    return 0;
}



static int read_u24(FILE* fp, unsigned int *u24){
    unsigned int tmp;
    if(fread(&tmp, 1, 3, fp) != 3){
        printf("Failed to read_u24!\n");
        return -1;
    }
    *u24 = ((tmp >> 16) & 0xFF)| ((tmp << 16) & 0xFF0000) | (tmp &0xFF00);
    return 0;
}


static int read_u32(FILE* fp, unsigned int *u32){
    unsigned int tmp;
    if(fread(&tmp, 1, 4, fp) != 4){
        printf("Failed to read_u32!\n");
        return -1;
    }
    *u32 = ((tmp >> 24) & 0xFF) ||  ((tmp >> 8) & 0xFF00)| ((tmp << 8) & 0xFF0000) | ((tmp << 24)&0xFF000000);
    return 0;
}

static int read_ts(FILE *fp, unsigned int *ts){
    unsigned int tmp;
    if(fread(&tmp, 1, 4, fp) !=4) {
        printf("Failed to read_ts!\n");
        return -1;
    }
    
    *ts = ((tmp >> 16) & 0xFF) | ((tmp << 16) & 0xFF0000) | (tmp & 0xFF00) | (tmp & 0xFF000000);
    
    return 0;
}

int  read_data(FILE* fp, RTMPPacket **pack){
    /*
        * tag header
        * 第一个字节 TT（Tag Type）, 0x08 音频，0x09 视频， 0x12 script
        * 2-4, Tag body 的长度， PreTagSize - Tag Header size
        * 5-7, 时间戳，单位是毫秒; script 它的时间戳是0
        * 第8个字节，扩展时间戳。真正时间戳结格 [扩展，时间戳] 一共是4字节。
        * 9-11, streamID, 0
        */
    unsigned int tt;
    unsigned int tag_data_size;
    unsigned int ts;
    unsigned int streamId;
    unsigned int tag_pre_size;

    int ret = -1;
    size_t data_size = 0;
    if(read_u8(fp, &tt)){
        goto __ERROR;
    }
    
    if(read_u24(fp, &tag_data_size)){
        goto __ERROR;
    }
    
    if(read_ts(fp, &ts)){
        goto __ERROR;
    }
    
    if(read_u24(fp, &streamId)){
        goto __ERROR;
    }
    data_size = fread((*pack)->m_body, 1, tag_data_size, fp);
    if(tag_data_size != data_size){
        printf("read data size error tag_data_size = %d, real data size = %d\n", tag_data_size, data_size);
        goto __ERROR;
    }
    (*pack)->m_headerType = RTMP_PACKET_SIZE_LARGE;
    (*pack)->m_nTimeStamp = ts;
    (*pack)->m_packetType = tt;
    (*pack)->m_nBodySize = tag_data_size;
    read_u32(fp, &tag_pre_size);
    ret = 0;
__ERROR:
    return ret;
    
}

static void send_data(FILE* fp, RTMP *rtmp){
    //1、创建RTMPPacket对象
    RTMPPacket *packet = NULL;
    unsigned int pre_ts = 0;
    packet = alloc_packet();
    packet->m_nInfoField2 = rtmp->m_stream_id;

    while (1) {
        //从flv读取文件
        //2.从flv文件中读取数据
        if(read_data(fp, &packet)){
            printf("over!\n");
            break;
        }
        //判断rtmp是否还处在链接状态
        if(!RTMP_IsConnected(rtmp)){
            printf("Disconnect....\n");
            break;
        }

        unsigned int diff = packet->m_nTimeStamp - pre_ts;
        usleep(diff * 1000);
        //发送数据
        RTMP_SendPacket(rtmp, packet, 0);
        pre_ts = packet->m_nTimeStamp;

        
    }
    
}




void push_stream(){
    char* rtmp_addr = "rtmp://localhost/live/room";

    char* flv = "/Users/yuanxuzhen/study/mac/PushStream/PushStream/output/test_yuv.flv";
    //读flv文件
    FILE* fp = open_flv(flv);
    
    //链接RTMP服务器
    RTMP* rtmp = connect_rtmp_server(rtmp_addr);
    
    //push video/audio data
    send_data(fp, rtmp);
    
}
